package com.twq.types.typeparam.contravariance

import com.twq.types.typeparam.{Animal, Cat}

/**
 * Created by tangweiqun on 2017/12/7.
 * 逆变
 */
////1、使用 - 符号定义T的逆变
abstract class Printer[-A] {
  def print(value: A): Unit
}


class AnimalPrinter extends Printer[Animal] {
  def print(animal: Animal): Unit =
    println("The animal's name is: " + animal.name)
}

class CatPrinter extends Printer[Cat] {
  def print(cat: Cat): Unit =
    println("The cat's name is: " + cat.name)
}


object ContravarianceTest {
  def main(args: Array[String]): Unit = {
    val myCat: Cat = new Cat("Boots")

    //2、如果Printer[Cat]知道怎么将Cat打印到控制台，
    // 而且Printer[Animal]知道怎样将Animal打印到控制台
    //那么Printer[Animal]将知道怎么将Cat打印到控制台
    //反过来则不行，因为Printer[Cat]不知道怎样打印任何的Animal到控制台
    def printMyCat(printer: Printer[Cat]): Unit = {
      printer.print(myCat)
    }

    val catPrinter: Printer[Cat] = new CatPrinter
    val animalPrinter: Printer[Animal] = new AnimalPrinter

    printMyCat(catPrinter)
    //3、Printer[Animal]是Printer[Cat]的子类
    printMyCat(animalPrinter)

    //4、里氏替换原则：
    // 如果类型T和U支持相同的操作方法，
    // 而且类型T中的方法的参数的类型是类型U中的方法的参数的类型的父类，
    // T中的方法的返回类型是U中的方法返回类型的子类(类型相等)，
    // 那我们可以说T是U的子类，就是说T可以替换U
  }
}
